package cn.rkylin.oms.common.collection;

import cn.rkylin.oms.common.function.Function;
import cn.rkylin.oms.common.function.IndexFunction;
import cn.rkylin.oms.common.function.Predicate;
import cn.rkylin.oms.common.function.ReduceFunction;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public final class Lists {

    public static <E> ArrayList<E> newArrayList(Iterator<E> iterator) {
        ArrayList<E> list = new ArrayList<>();
        while (iterator.hasNext()) {
            list.add(iterator.next());
        }
        return list;
    }

    public static <T, R> List<R> transform(List<T> list, Function<T, R> converter) {
        List<R> converted = new ArrayList<>();
        for (T item : list) {
            converted.add(converter.apply(item));
        }

        return converted;
    }

    public static <T, R> List<R> transform(List<T> list, IndexFunction<T, R> converter) {
        List<R> converted = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            converted.add(converter.apply(list.get(i), i));
        }

        return converted;
    }

    public static <T> List<T> filter(List<T> list, Predicate<T> predicate) {
        List<T> filtered = new ArrayList<>();
        for (T item : list) {
            if (predicate.test(item)) {
                filtered.add(item);
            }
        }

        return filtered;
    }

    public static <T, R> R reduce(List<T> list, ReduceFunction<T, R> function, R initValue) {
        R value = initValue;
        for (T item : list) {
            value = function.apply(value, item);
        }

        return value;
    }

    public static <T> boolean any(List<T> list, Predicate<T> predicate) {
        for (T item : list) {
            if (predicate.test(item)) {
                return true;
            }
        }

        return false;
    }

    public static <T> boolean every(List<T> list, Predicate<T> predicate) {
        for (T item : list) {
            if (!predicate.test(item)) {
                return false;
            }
        }

        return true;
    }

}
